using System;
using System.IO;
using System.Text;
using SexpSharp.Serialization;

namespace SexpSharp.Serialization.Tests
{
	[Serializable]
	public class Sample1
	{
		public bool b = true;
		public short s = 42;
		public int i = -1002;
		public long l = -32000;
		public string str = "I am the very model of a modern major general";
		public decimal d = 3.14159m;
	}

	[Serializable]
	public struct Sample2
	{
		public bool b;
		public short s;
		public int i;
		public long l;
		public string str;
		public decimal d;

		public object InitMe()
		{
			b = true;
			s = 42;
			i = -1002;
			l = -32000;
			str = "I am the very model of a modern major general";
			d = 3.14159m;
			return this;
		}
	}

	[Serializable,SexpFixed]
	public struct Fixed1
	{
		public bool b;
		public short s;
		public int i;
		public long l;
		public string str;
		public decimal d;

		public object InitMe()
		{
			b = true;
			s = 42;
			i = -1002;
			l = -32000;
			str = "I am the very model of a modern major general";
			d = 3.14159m;
			return this;
		}
	}

	[Serializable, SexpTypeName("sample-type-name")]
	public class Sample3
	{
		[SexpFieldName("some-bool")]
		public bool b = true;
		[SexpFieldName("some-short")]
		public short s = 42;
		[SexpFieldName("some-int")]
		public int i = -1002;
		[SexpFieldName("some-long")]
		public long l = -32000;
		[SexpFieldName("some-string")]
		public string str = "I am the very model of a modern major general";
		[SexpFieldName("some-decimal")]
		public decimal d = 3.14159m;
	}

	[Serializable,SexpFixed,SexpTypeName("new-type-name")]
	public struct Fixed2
	{
		public bool b;
		public short s;
		public int i;
		public long l;
		public string str;
		public decimal d;

		public object InitMe()
		{
			b = true;
			s = 42;
			i = -1002;
			l = -32000;
			str = "I am the very model of a modern major general";
			d = 3.14159m;
			return this;
		}
	}

    public enum TestEnum
    {
        ValueOne,
        ValueTwo,
        ValueThree
    }

    [SexpTypeName("test-enum")]
    public enum TestEnum2
    {
        ValueOne,
        ValueTwo,
        ValueThree
    }

    [Serializable]
    public class Cycle1
    {
        public Cycle2 cycle;
        public int foo;

        public override bool Equals(object o)
        {
            if (o is Cycle1)
            {
                return foo == ((Cycle1) o).foo;
            }
            return false;
        }
    }

    [Serializable]
    public class Cycle2
    {
        public Cycle1 cycle;
        public int foo;        

        public override bool Equals(object o)
        {
            if (o is Cycle2)
            {
                return foo == ((Cycle2) o).foo;
            }
            return false;
        }
    }

	public class Test3
	{
		public void a() {
			serialize(new Sample1());
		}

		public void b() {
			serialize(new Sample2().InitMe());
		}

		public void c() {
			serialize(new Sample3());
		}

		public void d() {
			serialize(new Fixed1().InitMe());
		}

		public void e() {
			serialize(new Fixed2().InitMe());
		}

		public void f() {
			deserialize("(serial-object #01# (SexpSharp.Serialization.Tests.Sample1 ((b (.b True)) (s (.s2 #002a#)) (i (.s4 #fffffc16#)) (l (.s8 #ffffffffffff8300#)) (str (.s \"I am the very model of a modern major general\")) (d (.D \"3.141590e+000\")))))");
		}

		public void g() {
			deserialize("(serial-object #01# (SexpSharp.Serialization.Tests.Sample2 ((b (.b True)) (s (.s2 #002a#)) (i (.s4 #fffffc16#)) (l (.s8 #ffffffffffff8300#)) (str (.s \"I am the very model of a modern major general\")) (d (.D \"3.141590e+000\")))))");
		}

		public void h() {
			deserialize("(serial-object #01# (sample-type-name ((some-bool (.b True)) (some-short (.s2 #002a#)) (some-int (.s4 #fffffc16#)) (some-long (.s8 #ffffffffffff8300#)) (some-string (.s \"I am the very model of a modern major general\")) (some-decimal (.D \"3.141590e+000\")))))");
		}

		public void i() {
			deserialize("(serial-object #01# (SexpSharp.Serialization.Tests.Fixed1 (True #002a# #fffffc16# #ffffffffffff8300# \"I am the very model of a modern major general\" \"3.141590e+000\")))");
		}

		public void j() {
			deserialize("(serial-object #01# (new-type-name (True #002a# #fffffc16# #ffffffffffff8300# \"I am the very model of a modern major general\" \"3.141590e+000\")))");
		}

        public void k()
        {
            TestEnum e = TestEnum.ValueOne;
            serialize(e);
            e = TestEnum.ValueTwo;
            serialize(e);
            e = TestEnum.ValueThree;
            serialize(e);
        }

        public void l()
        {
            TestEnum2 e = TestEnum2.ValueOne;
            serialize(e);
            e = TestEnum2.ValueTwo;
            serialize(e);
            e = TestEnum2.ValueThree;
            serialize(e);
        }

        public void m()
        {
            Cycle1 c1 = new Cycle1();
            Cycle2 c2 = new Cycle2();
            c1.cycle = c2;
            c1.foo = 1234;
            c2.cycle = c1;
            c2.foo = 4321;
            serialize(c1);
        }

		public static void Main(string[] argv)
		{
			Test3 t = new Test3();
			t.a();
			t.b();
			t.c();
			t.d();
			t.e();
			t.f();
			t.g();
			t.h();
			t.i();
			t.j();
            t.k();
            t.l();
            t.m();
		}

		static void deserialize(string expr)
		{
			MemoryStream s = new MemoryStream(new ASCIIEncoding().GetBytes(expr));
			object o = new SexpFormatter().Deserialize(s);
            Console.WriteLine(o);
		}

		static void serialize(object o)
		{
			SexpFormatter f = new SexpFormatter();
			f.SerializeFormat = Format.Advanced;
			f.Serialize(Console.OpenStandardError(), o);
            Console.Error.WriteLine();
		}
	}
}